﻿#include "framework.h"
#include <CommCtrl.h>
#include "MainWindow.h"
#include "Resource.h"

// 函数声明
static void MainWindow_Delete(MainWindow*);
static void MainWindow_DoModal(MainWindow*);
static void MainWindow_OnActivate(MainWindow*, WPARAM);
static void MainWindow_OnButtonMusicClicked(MainWindow*);
static void MainWindow_OnButtonPauseClicked(MainWindow*);
static void MainWindow_OnButtonStartClicked(MainWindow*);
static HBRUSH MainWindow_OnCtlColor(WPARAM, LPARAM);
static void MainWindow_OnDifficultyUp(MainWindow*, int);
static void MainWindow_OnGameOver(MainWindow*, BOOL);
static BOOL MainWindow_OnKeyPressed(MainWindow*, UINT);
static void MainWindow_OnPaint(MainWindow*);
static void MainWindow_OnScore(MainWindow*, int);
static void MainWindow_OnTimer(MainWindow*);
static INT_PTR CALLBACK MainWindow_Proc(HWND, UINT, WPARAM, LPARAM);

/**
 * 创建主窗口。
 */
MainWindow* New_MainWindow() {
    HWND buttonStart = NULL;
    HWND buttonPause = NULL;
    HWND buttonMusic = NULL;
    LONG style;
    int* parts;
    int lblWidth = 0;
    RECT windowRect = { 0 };
    HMODULE module = GetModuleHandle(NULL);
    MainWindow* mainWindow = (MainWindow*)calloc(1, sizeof(MainWindow));

    // 初始化数据
    mainWindow->mButtonPauseImage = LoadBitmap(module, MAKEINTRESOURCE(IDB_BUTTON_PAUSE));
    mainWindow->mButtonPlayMusicImage = LoadBitmap(module, MAKEINTRESOURCE(IDB_BUTTON_MUSIC_PLAY));
    mainWindow->mButtonResumeImage = LoadBitmap(module, MAKEINTRESOURCE(IDB_BUTTON_RESUME));
    mainWindow->mButtonStartImage = LoadBitmap(module, MAKEINTRESOURCE(IDB_BUTTON_START));
    mainWindow->mButtonStopMusicImage = LoadBitmap(module, MAKEINTRESOURCE(IDB_BUTTON_MUSIC_STOP));
    mainWindow->mHandle = CreateDialog(NULL, MAKEINTRESOURCE(IDD_MAIN_WINDOW), NULL, MainWindow_Proc);
    SetWindowLongPtr(mainWindow->mHandle, GWLP_USERDATA, (LONG_PTR)mainWindow);
    mainWindow->mImage = LoadBitmap(module, MAKEINTRESOURCE(IDB_MAIN_WINDOW));
    mainWindow->mImageDC = CreateCompatibleDC(GetDC(mainWindow->mHandle));
    SelectObject(mainWindow->mImageDC, mainWindow->mImage);
    style = WS_CHILD | WS_VISIBLE | CCS_BOTTOM;
    mainWindow->mStatusBar = CreateStatusWindow(style, NULL, mainWindow->mHandle, 0);

    // 初始化函数
    mainWindow->doModal = MainWindow_DoModal;

    // 设置按钮图片
    buttonStart = GetDlgItem(mainWindow->mHandle, IDC_BUTTON_START);
    buttonPause = GetDlgItem(mainWindow->mHandle, IDC_BUTTON_PAUSE);
    buttonMusic = GetDlgItem(mainWindow->mHandle, IDC_BUTTON_MUSIC);

    style = GetWindowLong(buttonStart, GWL_STYLE) | BS_BITMAP;
    SetWindowLong(buttonStart, GWL_STYLE, style);
    SendMessage(buttonStart, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonStartImage);

    style = GetWindowLong(buttonPause, GWL_STYLE) | BS_BITMAP;
    SetWindowLong(buttonPause, GWL_STYLE, style);
    SendMessage(buttonPause, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonPauseImage);

    style = GetWindowLong(buttonMusic, GWL_STYLE) | BS_BITMAP;
    SetWindowLong(buttonMusic, GWL_STYLE, style);
    SendMessage(buttonMusic, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonPlayMusicImage);

    // 设置状态栏的格的宽度
    GetWindowRect(mainWindow->mHandle, &windowRect);
    lblWidth = (windowRect.right - windowRect.left) / STATUS_BAR_PART_COUNT;
    parts = (int*)calloc(STATUS_BAR_PART_COUNT, sizeof(int));
    for (int i = 0; i < STATUS_BAR_PART_COUNT; i++) {
        parts[i] = lblWidth * (i + 1);
    }
    SendMessage(mainWindow->mStatusBar, SB_SETPARTS, STATUS_BAR_PART_COUNT, (LPARAM)parts);
    free(parts);

    // 设置状态栏第1格的文字
    MainWindow_OnDifficultyUp(mainWindow, 1);

    // 设置状态栏第2格的文字
    MainWindow_OnScore(mainWindow, 0);

    // 创建游戏区域
    mainWindow->mGameBoard = New_GameBoard(mainWindow->mHandle, GAME_BOARD_X, GAME_BOARD_Y, GAME_BOARD_WIDTH, GAME_BOARD_HEIGHT);

    // 创建预览区域
    mainWindow->mPreview = New_GameBoard(mainWindow->mHandle, PREVIEW_X, PREVIEW_Y, PREVIEW_WIDTH, PREVIEW_HEIGHT);

    // 创建游戏
    mainWindow->mGame = New_Game(mainWindow->mHandle, mainWindow->mGameBoard->mHandle,
        mainWindow->mGameBoard->mDrawer, mainWindow->mPreview->mHandle, mainWindow->mPreview->mDrawer);

    return mainWindow;
}

/**
 * 删除主窗口。
 * @param mainWindow    主窗口
 */
static void MainWindow_Delete(MainWindow* mainWindow) {
    mainWindow->mPreview->deleteSelf(mainWindow->mPreview);
    mainWindow->mGameBoard->deleteSelf(mainWindow->mGameBoard);
    mainWindow->mGame->deleteSelf(mainWindow->mGame);
    DeleteDC(mainWindow->mImageDC);
    DestroyWindow(mainWindow->mHandle);
    free(mainWindow);
}

/**
 * 以模态显示窗口。
 * @param mainWindow    主窗口
 */
static void MainWindow_DoModal(MainWindow* mainWindow) {
    MSG msg = { 0 };
    BOOL handledKeyPress = FALSE;

    // 显示窗口
    ShowWindow(mainWindow->mHandle, SW_SHOW);

    // 窗口事件循环
    while (GetMessage(&msg, NULL, 0, 0)) {
        if (msg.message == WM_KEYDOWN) {
            handledKeyPress = MainWindow_OnKeyPressed(mainWindow, msg.wParam);
        }
        if (!handledKeyPress) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        handledKeyPress = FALSE;
    }
}

/**
 * 窗口活动事件的响应函数。
 * @param mainWindow    主窗口
 * @param wParam        如果这个参数的低16位为 WA_INACTIVE 则表示窗口进入不活动状态
 */
static void MainWindow_OnActivate(MainWindow* mainWindow, WPARAM wParam) {
    if (mainWindow->mGame->mStatus == PLAYING && wParam == WA_INACTIVE) {
        MainWindow_OnButtonPauseClicked(mainWindow);
    }
}

/**
 * "播放音乐"按钮的单击响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnButtonMusicClicked(MainWindow* mainWindow) {
    HWND buttonMusic = GetDlgItem(mainWindow->mHandle, IDC_BUTTON_MUSIC);
    BOOL playingMusic = mainWindow->mGame->playMusic(mainWindow->mGame);

    if (playingMusic) {
        SendMessage(buttonMusic, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonStopMusicImage);
    } else {
        SendMessage(buttonMusic, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonPlayMusicImage);
    }
}

/**
 * "暂停"按钮的单击响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnButtonPauseClicked(MainWindow* mainWindow) {
    HWND buttonPause = GetDlgItem(mainWindow->mHandle, IDC_BUTTON_PAUSE);
    mainWindow->mGame->pause(mainWindow->mGame);

    if (mainWindow->mGame->mStatus == PAUSED) {
        SendMessage(buttonPause, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonResumeImage);
    } else if (mainWindow->mGame->mStatus == PLAYING) {
        SendMessage(buttonPause, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonPauseImage);
    }
}

/**
 * "开始"按钮的单击响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnButtonStartClicked(MainWindow* mainWindow) {
    HWND buttonPause = GetDlgItem(mainWindow->mHandle, IDC_BUTTON_PAUSE);

    // 游戏开始
    mainWindow->mGame->start(mainWindow->mGame);

    // 设置按钮状态
    EnableWindow(buttonPause, TRUE);

    // 设置按钮图片
    SendMessage(buttonPause, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)mainWindow->mButtonPauseImage);

    // 设置状态栏文字
    MainWindow_OnDifficultyUp(mainWindow, 1);
    MainWindow_OnScore(mainWindow, 0);
}

/**
 * 控件颜色事件的响应方法。
 * @param wParam    绘图者
 * @param lParam    控件
 * @return 控件的背景画刷
 */
static HBRUSH MainWindow_OnCtlColor(WPARAM wParam, LPARAM lParam) {
    HDC drawer = (HDC)wParam;
    HWND window = (HWND)lParam;
    HBRUSH brush = NULL;
    int id = GetDlgCtrlID(window);

    if (id == IDC_LABEL_HELP) {
        SetBkMode(drawer, TRANSPARENT);
        brush = (HBRUSH)GetStockObject(NULL_BRUSH);
    } else {
        brush = (HBRUSH)DefWindowProc(GetParent(window), WM_CTLCOLORSTATIC, wParam, lParam);
    }
    return brush;
}

/**
 * 难度增加事件的响应函数。
 * @param mainWindow    主窗口
 * @param difficulty    难度
 */
static void MainWindow_OnDifficultyUp(MainWindow* mainWindow, int difficulty) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    TCHAR temp[STRING_BUF_LEN] = { 0 };

    LoadString(NULL, IDS_DIFFICULTY, text, STRING_BUF_LEN);
    _itot_s(difficulty, temp, STRING_BUF_LEN, 10);
    _tcscat_s(text, STRING_BUF_LEN, temp);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 0, (LPARAM)text);
}

/**
 * 游戏结束事件的响应函数。
 * @param mainWindow    主窗口
 * @param isWon         胜利则为 TRUE，否则为 FALSE
 */
static void MainWindow_OnGameOver(MainWindow* mainWindow, BOOL isWon) {
    TCHAR text[STRING_BUF_LEN] = { 0 };

    if (isWon) {
        LoadString(NULL, IDS_WON, text, STRING_BUF_LEN);
    } else {
        LoadString(NULL, IDS_LOST, text, STRING_BUF_LEN);
    }
    MessageBox(mainWindow->mHandle, text, _T(" "), MB_ICONINFORMATION);
    EnableWindow(GetDlgItem(mainWindow->mHandle, IDC_BUTTON_PAUSE), FALSE);
}

/**
 * 按键事件的响应函数。
 * @param mainWindow    主窗口
 * @param key           按键
 * @return 事件在此被处理则返回 TRUE，否则返回 FALSE
 */
static BOOL MainWindow_OnKeyPressed(MainWindow* mainWindow, UINT key) {
    return mainWindow->mGame->onKeyPressed(mainWindow->mGame, key);
}

/**
 * 重绘事件的响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnPaint(MainWindow* mainWindow) {
    BITMAP bmpInfo = { 0 };
    PAINTSTRUCT ps = { 0 };

    GetObject(mainWindow->mImage, sizeof(bmpInfo), &bmpInfo);
    BeginPaint(mainWindow->mHandle, &ps);
    BitBlt(ps.hdc, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, mainWindow->mImageDC, 0, 0, SRCCOPY);
    EndPaint(mainWindow->mHandle, &ps);
}

/**
 * 得分事件的响应函数。
 * @param mainWindow    主窗口
 * @param score         得分
 */
static void MainWindow_OnScore(MainWindow* mainWindow, int score) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    TCHAR temp[STRING_BUF_LEN] = { 0 };

    LoadString(NULL, IDS_SCORE, text, STRING_BUF_LEN);
    _itot_s(score, temp, STRING_BUF_LEN, 10);
    _tcscat_s(text, STRING_BUF_LEN, temp);
    SendMessage(mainWindow->mStatusBar, SB_SETTEXT, 1, (LPARAM)text);
}

/**
 * 定时器事件的响应函数。
 * @param mainWindow    主窗口
 */
static void MainWindow_OnTimer(MainWindow* mainWindow) {
    mainWindow->mGame->onTimer(mainWindow->mGame);
}

/**
 * 窗口过程函数。
 * @param window    窗口
 * @param message   事件标识
 * @param wParam    事件相关信息
 * @param lParam    事件相关信息
 * @return 事件在此被处理则返回 TRUE，否则返回 FALSE
 */
static INT_PTR CALLBACK MainWindow_Proc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    MainWindow* mainWindow = (MainWindow*)GetWindowLongPtr(window, GWLP_USERDATA);
    int id = LOWORD(wParam);

    switch (message) {
        case UM_DIFFICULTY_UP:
            MainWindow_OnDifficultyUp(mainWindow, wParam);
            return TRUE;
        case UM_GAME_OVER:
            MainWindow_OnGameOver(mainWindow, wParam);
            return TRUE;
        case UM_SCORE:
            MainWindow_OnScore(mainWindow, wParam);
            return TRUE;
        case WM_ACTIVATE:
            MainWindow_OnActivate(mainWindow, wParam);
            return TRUE;
        case WM_COMMAND:
            switch (id) {
                case IDC_BUTTON_MUSIC:
                    MainWindow_OnButtonMusicClicked(mainWindow);
                    return TRUE;
                case IDC_BUTTON_PAUSE:
                    MainWindow_OnButtonPauseClicked(mainWindow);
                    return TRUE;
                case IDC_BUTTON_START:
                    MainWindow_OnButtonStartClicked(mainWindow);
                    return TRUE;
                case IDCANCEL:
                    MainWindow_Delete(mainWindow);
                    return TRUE;
            }
            break;
        case WM_CTLCOLORSTATIC:
            return (INT_PTR)MainWindow_OnCtlColor(wParam, lParam);
        case WM_DESTROY:
            PostQuitMessage(0);
            return TRUE;
        case WM_PAINT:
            MainWindow_OnPaint(mainWindow);
            return TRUE;
            break;
        case WM_TIMER:
            MainWindow_OnTimer(mainWindow);
            return TRUE;
            break;
    }
    return FALSE;
}
